package com.sanglh.tutorial.common.util;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.location.LocationManager;
import android.media.AudioManager;
import android.net.ConnectivityManager;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.PowerManager;
import android.os.Vibrator;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;

import com.sanglh.tutorial.common.base.Logging;

public class SettingsUtils {

	/**
	 * MOBILE DATA
	 */
	// ===================================================================================================
	public static void setMobileDataEnabled(Context context, boolean enabled) {
		ConnectivityManager connectivityManager = (ConnectivityManager) context
				.getSystemService(Context.CONNECTIVITY_SERVICE);
		try {
			Class<?> connectivityManagerClass = Class
					.forName(connectivityManager.getClass().getName());
			Field mService = connectivityManagerClass
					.getDeclaredField("mService");
			mService.setAccessible(true);
			Object iConnectivityManager = mService.get(connectivityManager);
			Class<?> iConnectivityManagerClass = Class
					.forName(iConnectivityManager.getClass().getName());
			Method setMobileDataEnabled = iConnectivityManagerClass
					.getDeclaredMethod("setMobileDataEnabled", Boolean.TYPE);
			setMobileDataEnabled.setAccessible(true);
			setMobileDataEnabled.invoke(iConnectivityManager, enabled);
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	public static void toggleMobileData(Context context) {
		ConnectivityManager connectivityManager = (ConnectivityManager) context
				.getSystemService(Context.CONNECTIVITY_SERVICE);
		try {
			Class<?> connectivityManagerClass = Class
					.forName(connectivityManager.getClass().getName());
			Field mService = connectivityManagerClass
					.getDeclaredField("mService");
			mService.setAccessible(true);
			Object iConnectivityManager = mService.get(connectivityManager);
			Class<?> iConnectivityManagerClass = Class
					.forName(iConnectivityManager.getClass().getName());
			Method getMobileDataEnabled = iConnectivityManagerClass
					.getDeclaredMethod("getMobileDataEnabled", null);
			Boolean enabled = (Boolean) getMobileDataEnabled
					.invoke(iConnectivityManager);
			Method setMobileDataEnabled = iConnectivityManagerClass
					.getDeclaredMethod("setMobileDataEnabled", Boolean.TYPE);
			setMobileDataEnabled.setAccessible(true);
			setMobileDataEnabled.invoke(iConnectivityManager, !enabled);
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	/**
	 * GPS
	 */
	// ===================================================================================================
	public static boolean canToggleGPS(Context context) {
		PackageManager pacman = context.getPackageManager();
		PackageInfo pacInfo = null;
		try {
			pacInfo = pacman.getPackageInfo("com.android.settings",
					PackageManager.GET_RECEIVERS);
		} catch (NameNotFoundException e) {
			return false;
		}
		if (pacInfo != null) {
			for (ActivityInfo actInfo : pacInfo.receivers) {
				if (actInfo.name
						.equals("com.android.settings.widget.SettingsAppWidgetProvider")
						&& actInfo.exported) {
					return true;
				}
			}
		}
		return false;
	}

	public static boolean isGpsEnabled(Context context) {
		LocationManager locationManager = (LocationManager) context
				.getSystemService(Context.LOCATION_SERVICE);
		return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
	}

	public static void toggleGPS(Context context) {
		if (!canToggleGPS(context)) {
			Logging.log("cannotToggleGPS");
			return;
		}
		Intent intentGPS = new Intent();
		intentGPS.setClassName("com.android.settings",
				"com.android.settings.widget.SettingsAppWidgetProvider");
		intentGPS.addCategory(Intent.CATEGORY_ALTERNATIVE);
		intentGPS.setData(Uri.parse("3"));
		context.sendBroadcast(intentGPS);
	}

	@SuppressWarnings("deprecation")
	public static void setGPSEnabled(Context context, boolean enabled) {
		if (!canToggleGPS(context)) {
			return;
		}
		String provider = Settings.Secure.getString(
				context.getContentResolver(),
				Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
		if (provider.contains("gps") ^ enabled) {
			Intent intentGPS = new Intent();
			intentGPS.setClassName("com.android.settings",
					"com.android.settings.widget.SettingsAppWidgetProvider");
			intentGPS.addCategory(Intent.CATEGORY_ALTERNATIVE);
			intentGPS.setData(Uri.parse("3"));
			context.sendBroadcast(intentGPS);
		}
	}

	/**
	 * BRIGHTNESS
	 */
	// ===================================================================================================
	public static void setBrightMode(Context context, boolean isAuto) {
		Settings.System.putInt(context.getContentResolver(),
				Settings.System.SCREEN_BRIGHTNESS_MODE,
				isAuto ? Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC
						: Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
	}

	/**
	 * @param brightness
	 *            : 0 - 255
	 */
	public static void setBrightness(Context context, int brightness) {
		if (brightness < 0) {
			return;
		}
		setBrightMode(context, false);
		Settings.System.putInt(context.getContentResolver(),
				Settings.System.SCREEN_BRIGHTNESS, brightness);
	}

	public static int getBrightness(Context context) {
		try {
			return Settings.System.getInt(context.getContentResolver(),
					Settings.System.SCREEN_BRIGHTNESS);
		} catch (SettingNotFoundException e) {
			return -1;
		}
	}

	public static int getBrightnessMode(Context context) {
		try {
			return Settings.System.getInt(context.getContentResolver(),
					Settings.System.SCREEN_BRIGHTNESS_MODE);
		} catch (SettingNotFoundException e) {
			return -1;
		}
	}

	/**
	 * WIFI
	 */
	// ===================================================================================================
	public static boolean isWifiEnabled(Context context) {
		WifiManager wifiManager = (WifiManager) context
				.getSystemService(Context.WIFI_SERVICE);
		int wifiState = wifiManager.getWifiState();
		return wifiState == WifiManager.WIFI_STATE_ENABLED;
	}

	public static boolean setWifiEnabled(Context context, boolean enabled) {
		WifiManager wifiManager = (WifiManager) context
				.getSystemService(Context.WIFI_SERVICE);
		return wifiManager.setWifiEnabled(enabled);
	}

	public static void toggleWifi(Context context) {
		WifiManager wifiManager = (WifiManager) context
				.getSystemService(Context.WIFI_SERVICE);
		wifiManager.setWifiEnabled(!isWifiEnabled(context));
	}

	/**
	 * BLUETOOTH
	 */
	// ===================================================================================================
	public static boolean isBluetoothSupported() {
		BluetoothAdapter bluetoothAdapter = BluetoothAdapter
				.getDefaultAdapter();
		return bluetoothAdapter != null;
	}

	public static boolean isBluetoothEnabled(Context context) {
		if (!isBluetoothSupported()) {
			return false;
		}
		BluetoothAdapter bluetoothAdapter = BluetoothAdapter
				.getDefaultAdapter();

		return bluetoothAdapter.isEnabled();
	}

	public static boolean setBluetoothEnabled(Context context, boolean enabled) {
		if (!isBluetoothSupported()) {
			return false;
		}
		BluetoothAdapter bluetoothAdapter = BluetoothAdapter
				.getDefaultAdapter();
		return enabled ? bluetoothAdapter.enable() : bluetoothAdapter.disable();

	}

	public static void toggleBluetoothEnabled(Context context) {
		if (!isBluetoothSupported()) {
			return;
		}
		setBluetoothEnabled(context, !isBluetoothEnabled(context));

	}

	/**
	 * AIRPLANE MODE
	 */
	@SuppressWarnings("deprecation")
	@SuppressLint({ "NewApi" })
	// ===================================================================================================
	public static boolean isAirPlaneModeEnable(Context context) {
		int sdk = Build.VERSION.SDK_INT;
		if (sdk < 17) {
			return Settings.System.getInt(context.getContentResolver(),
					Settings.System.AIRPLANE_MODE_ON, 0) != 0;

		}
		return Settings.Global.getInt(context.getContentResolver(),
				Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
	}

	@SuppressWarnings("deprecation")
	@SuppressLint({ "NewApi" })
	public static void setAirPlaneModeEnable(Context context, boolean enabled) {
		int sdk = Build.VERSION.SDK_INT;

		if (sdk < Build.VERSION_CODES.JELLY_BEAN_MR1) {
			// Change the system setting
			Settings.System.putInt(context.getContentResolver(),
					Settings.System.AIRPLANE_MODE_ON, enabled ? 1 : 0);

		} else {
			// Change the system setting
			Settings.Global.putInt(context.getContentResolver(),
					Settings.Global.AIRPLANE_MODE_ON, enabled ? 1 : 0);

		}
		// Post the intent
		Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
		intent.putExtra("state", enabled);
		context.sendBroadcast(intent);

	}

	public static void toggleAirPlaneMode(Context context) {
		setAirPlaneModeEnable(context, !isAirPlaneModeEnable(context));
	}

	/**
	 * RING MODE
	 */
	// ===================================================================================================
	@SuppressLint("NewApi")
	public static boolean isVibrateSupported(Context context) {
		Vibrator vibrator = (Vibrator) context
				.getSystemService(Context.VIBRATOR_SERVICE);
		if (Build.VERSION.SDK_INT < 11) {
			return (vibrator == null);
		}
		return (vibrator == null || !vibrator.hasVibrator());
	}

	public static int getSoundMode(Context context) {
		AudioManager am = (AudioManager) context
				.getSystemService(Context.AUDIO_SERVICE);
		return am.getRingerMode();

	}

	public static void setSoundMode(Context context, int ringerMode) {
		AudioManager am = (AudioManager) context
				.getSystemService(Context.AUDIO_SERVICE);
		am.setRingerMode(ringerMode);
	}

	public static void switchSoundMode(Context context) {
		AudioManager am = (AudioManager) context
				.getSystemService(Context.AUDIO_SERVICE);
		if (isVibrateSupported(context)) {
			am.setRingerMode((getSoundMode(context) + 1) % 3);
		} else {
			am.setRingerMode((getSoundMode(context) + 2) % 3);
		}

	}

	/**
	 * CAMERA
	 */
	// ===================================================================================================
	public static boolean havingCameraHardware(Context context) {
		return context.getPackageManager().hasSystemFeature(
				PackageManager.FEATURE_CAMERA);
	}

	public static boolean havingFrontCameraHardware(Context context) {
		return Camera.getNumberOfCameras() > 1;
	}

	public static boolean isFlashSupported(Context context) {
		return context.getPackageManager().hasSystemFeature(
				PackageManager.FEATURE_CAMERA_FLASH);
	}

	public static Camera getBackCamera() {
		Camera c = null;
		try {
			c = Camera.open(); // attempt to get a Camera instance
		} catch (Exception e) {
			// Camera is not available (in use or does not exist)
		}
		return c; // returns null if camera is unavailable
	}

	public static Camera getFrontCamera() {
		int cameraCount = 0;
		Camera camera = null;
		Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
		cameraCount = Camera.getNumberOfCameras();
		for (int camIdx = 0; camIdx < cameraCount; camIdx++) {
			Camera.getCameraInfo(camIdx, cameraInfo);
			if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
				try {
					camera = Camera.open(camIdx);
				} catch (RuntimeException e) {
					// Camera is not available (in use or does not exist)
				}
			}
		}
		return camera;
	}

	public static void setFlashEnabled(Context context, Camera camera,
			boolean enabled) {
		if (!havingCameraHardware(context) || !isFlashSupported(context)) {
			return;
		}
		if (camera == null) {
			return;
		}
		Parameters parameters = camera.getParameters();
		parameters.setFlashMode(enabled ? Parameters.FLASH_MODE_TORCH
				: Parameters.FLASH_MODE_OFF);
		camera.setParameters(parameters);
		if (enabled) {
			camera.startPreview();
		} else {
			camera.stopPreview();
		}
	}

	public static void releaseCamera(Camera camera) {
		if (camera != null) {
			camera.release();
			camera = null;
		}

	}

	/**
	 * POWER
	 */
	// ===================================================================================================
	public static void powerReboot(Context context) {
		PowerManager powerManager = (PowerManager) context
				.getSystemService(Context.POWER_SERVICE);
		Class<?> powerManagerClass = powerManager.getClass();
		try {
			Field mService = powerManagerClass.getDeclaredField("mService");
			mService.setAccessible(true);
			Object iPowerManagerObject = mService.get(powerManager);
			Class<?> iPowerManagerClass = Class.forName(iPowerManagerObject
					.getClass().getName());
			Method reboot = iPowerManagerClass.getDeclaredMethod("reboot",
					boolean.class, String.class, boolean.class);
			reboot.setAccessible(true);
			// reboot(boolean confirm, java.lang.String reason, boolean wait)
			reboot.invoke(iPowerManagerObject, false, "reboot", true);
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	public static void logAllMethod(Class<?> clazz) {
		try {
			// TEST
			Method[] methods = clazz.getMethods();
			for (Method method : methods) {
				Logging.log("method " + method.getName());
				Class<?>[] params = method.getParameterTypes();
				for (Class<?> param : params) {
					Logging.log("param " + param.getName());
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	/**
	 * ROTATION
	 */
	// ===================================================================================================
	public static boolean isAutoOrientationEnabled(Context context) {
		return Settings.System.getInt(context.getContentResolver(),
				Settings.System.ACCELEROMETER_ROTATION, 0) == 1;
	}

	public static void setAutoOrientationEnabled(Context context,
			boolean enabled) {
		Settings.System.putInt(context.getContentResolver(),
				Settings.System.ACCELEROMETER_ROTATION, enabled ? 1 : 0);
	}

	public static void toggleAutoOrientation(Context context) {
		Settings.System.putInt(context.getContentResolver(),
				Settings.System.ACCELEROMETER_ROTATION,
				isAutoOrientationEnabled(context) ? 0 : 1);
	}

}
